#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "ohos_types.h"
#include "cmsis_os2.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"
#include "iot_uart.h"
#include "iot_i2c.h"
#include "u8g2.h"

#define IOT_UART 1

// 传感器数据结构体
typedef struct {
    int pm2_5;         // PM2.5，单位 ug/m³
    int co2;           // CO2，单位 PPM
    float temperature; // 温度
    float humidity;    // 湿度
} SENSOR_DATA;

u8g2_t u8g2;

uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    static uint8_t buffer[32];
    static uint8_t buf_idx;
    uint8_t *data;

    switch (msg)
    {
        case U8X8_MSG_BYTE_SEND:
            data = (uint8_t*) arg_ptr;
            while (arg_int > 0)
            {
                buffer[buf_idx++] = *data;
                data++;
                arg_int--;
            }
            break;
        case U8X8_MSG_BYTE_INIT:
            // GPIO0 复用为 I2C1 SDA
            IoTGpioInit(0);
            IoTGpioSetFunc(0, IOT_GPIO_FUNC_GPIO_0_I2C1_SDA);
            IoTGpioSetDir(0, IOT_GPIO_DIR_OUT);
            // GPIO1 复用为 I2C1 SCL
            IoTGpioInit(1);
            IoTGpioSetFunc(1, IOT_GPIO_FUNC_GPIO_1_I2C1_SCL);
            IoTGpioSetDir(1, IOT_GPIO_DIR_OUT);
            // 初始化 I2C1，速率 400kbps
            int ret = IoTI2cInit(1, 400000);
            if (ret != IOT_SUCCESS)
            {
                printf("Failed to init I2C! Error=%d\n", ret);
                return 0;
            }
            break;
        case U8X8_MSG_BYTE_SET_DC:
            break;
        case U8X8_MSG_BYTE_START_TRANSFER:
            buf_idx = 0;
            break;
        case U8X8_MSG_BYTE_END_TRANSFER:
            IoTI2cWrite(1, u8x8_GetI2CAddress(u8x8), buffer, buf_idx);
            break;
        default:
            return 0;
    }
    return 1;
}

uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    uint8_t i;
    switch(msg)
    {
        case U8X8_MSG_GPIO_AND_DELAY_INIT:
            break;
        case U8X8_MSG_DELAY_NANO:
            usleep(1);
            break;
        case U8X8_MSG_DELAY_MILLI:
            usleep(arg_int * 1000);
            break;
        default:
            return 0;
    }
    return 1;
}

int SendCommand(uint8_t cmd, uint16_t data)
{
    uint8_t buffer[7] = {0x42, 0x4D, cmd, (data & 0xFF00) >> 8, data & 0xFF};
    // 计算校验和
    uint16_t checksum = 0;
    for (int i = 0; i < 5; i++)
        checksum += buffer[i];
    buffer[5] = (checksum & 0xFF00) >> 8;
    buffer[6] = checksum & 0xFF;
    // 通过串口 1 发送指令
    return IoTUartWrite(IOT_UART, buffer, sizeof(buffer));
}

int ReceiveData(SENSOR_DATA *data)
{
    uint8_t buffer[24] = {0};
    // 通过串口 1 接收数据
    int ret = IoTUartRead(IOT_UART, buffer, sizeof(buffer));
    if (buffer[0] != 0x42 || buffer[1] != 0x4D)
        return -1;
    // 解析数据
    data->pm2_5 = buffer[4] << 8 | buffer[5];
    data->co2 = buffer[12] << 8 | buffer[13];
    data->temperature = (buffer[14] << 8 | buffer[15]) / 10.0f;
    data->humidity = (buffer[16] << 8 | buffer[17]) / 10.0f;
    uint16_t checksum = 0;
    for (int i = 0; i < 22; i++)
        checksum += buffer[i];
    if (((checksum & 0xFF00) >> 8) != buffer[22] || (checksum & 0xFF) != buffer[23])
    {
        printf("Received data checksum error! ret=%d\n", ret);
    }
    return ret;
}

static void SensorTask(void)
{
    IotUartAttribute uart_attr =
    {
        .baudRate = 9600,
        .dataBits = IOT_UART_DATA_BIT_8,
        .stopBits = IOT_UART_STOP_BIT_1,
        .parity   = IOT_UART_PARITY_NONE,
        .rxBlock  = IOT_UART_BLOCK_STATE_BLOCK,
        .txBlock  = IOT_UART_BLOCK_STATE_BLOCK,
        .pad      = 0,
    };
    // 初始化 UART1
    IoTUartInit(IOT_UART, &uart_attr);
    // 初始化屏幕
    u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_gpio_and_delay);
    u8g2_InitDisplay(&u8g2);
    u8g2_SetPowerSave(&u8g2, 0);
    u8g2_SetFont(&u8g2, u8g2_font_6x12_mr);

    SENSOR_DATA data;
    while (1)
    {
        // 读取传感器数据
        SendCommand(0xab, 0);
        ReceiveData(&data);
        // 绘制文字
        u8g2_ClearBuffer(&u8g2);
        char str[20];
        u8g2_DrawStr(&u8g2, 0, 12, "Air quality");
        snprintf(str, sizeof(str), "PM2.5: %dug/m3", data.pm2_5);
        u8g2_DrawStr(&u8g2, 0, 24, str);
        snprintf(str, sizeof(str), "CO2: %dPPM", data.co2);
        u8g2_DrawStr(&u8g2, 0, 36, str);
        snprintf(str, sizeof(str), "Temperature: %.1f", data.temperature);
        u8g2_DrawStr(&u8g2, 0, 48, str);
        snprintf(str, sizeof(str), "Humidity: %.1f%%", data.humidity);
        u8g2_DrawStr(&u8g2, 0, 60, str);
        u8g2_SendBuffer(&u8g2);
        // 等待 1 秒
        sleep(1);
    }
}

void SensorExample(void)
{
    osThreadAttr_t attr;
    attr.name = "SensorTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 4096;
    attr.priority = osPriorityNormal;
    if (osThreadNew((osThreadFunc_t) SensorTask, NULL, &attr) == NULL)
    {
        printf("Failed to create SensorTask!\n");
    }
}

SYS_RUN(SensorExample);
